﻿using System;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using RainEngine;
using RainEngine.SceneManagement;
using RainEngine.SceneNodes;

namespace SceneEditor
{
    /// <summary>
    /// 用于节点选择的委托
    /// </summary>
    /// <param name="node"></param>
    public delegate void ItemSelected(object node);    

    /// <summary>
    /// Game对象
    /// </summary>
    public class SceneEditor : RainGE
    {
        /// <summary>
        /// 当节点被选择时对应的事件
        /// </summary>
        public event ItemSelected ItemSelected;      

        #region 构造函数和私用成员
        
        // 编辑器使用的Scene类
        public Scene     viewScene;    
        
        // 当前被选择的节点
        private SceneNode           selectedNode;        

        /// <summary>
        /// 获取当前被选择的SceneNode
        /// </summary>
        public SceneNode SelectedNode { get { return selectedNode; } }

        /// <summary>
        /// 以一个IEditorHost接口为参数的构造函数。
        /// </summary>
        /// <param name="txnaForm"></param>
        public SceneEditor(IEditorHost winForm) : base(winForm)
        {            
            winForm.Editor = this;          
        }

        #endregion

        #region 重写的方法
        
        /// <summary>
        /// 初始化
        /// </summary>
        protected override void Initialize()
        {
            base.Initialize();

            // 将fps设置为30帧每秒，在WinForm中设置更高的fps没什么意义
            TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 33);
            viewScene = new ViewScene(this);
            // 将场景添加到场景管理器
            SceneManager.AddScene(viewScene );            
            
        }
                
        /// <summary>
        /// 设置状态栏的文字
        /// </summary>
        /// <param name="gameTime"></param>
        protected override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
                  
            StatusStrip sst = ((MainForm)winForm).statusStrip1;
            sst.Items[0].Text = "相机位置：" + viewScene.Camera.Pose.Position.ToString();
            sst.Items[1].Text = "场景中的节点数量：" + viewScene.NodesCount.ToString();

            VisualizeSelection();
        }

        #endregion
        
        /// <summary>
        /// 在场景中添加一个SceneNode
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public bool AddNode(SceneNode node)
        {
            // 调用Scene的AddNode方法，如果成功则返回true
            return viewScene.AddNode(node);
        }       

        /// <summary>
        /// 根据给定鼠标坐标在视口中进行拾取检测。
        /// </summary>
        /// <param name="x">屏幕x坐标</param>
        /// <param name="y">屏幕y坐标</param>
        public void PickViewPort(int x, int y)
        {
            SceneNode node = SceneManager.Pickor.PickBB(x, y);
            if (node != null)
                SetSelection(node);
            else
                SetSelection(null);
        }

        /// <summary>
        /// 处理场景中节点的选择。当场景中的节点被选择时需要引发ItemSelected事件
        /// </summary>
        /// <param name="node">要处理的场景节点</param>
        public void SetSelection(object node)
        {
            // 首先判断是否是SceneNode
            if (node is SceneNode)
            {
                // 如果这个对象就是上一次选择的对象，则直接返回
                if (selectedNode == node)
                    return;

                selectedNode = (SceneNode)node as SceneNode;
                VisualizeSelection();
                ItemSelected(selectedNode);
            }
            else
            {
                selectedNode = null;
                ItemSelected(node);
            }            
        }

        /// <summary>
        /// 绘制所选节点的包围盒。
        /// </summary>
        public void VisualizeSelection()
        {
            if (selectedNode == null)
                return;

            Renderable3DSceneNode rsn = selectedNode as Renderable3DSceneNode;
            if (rsn != null)
            {                
                viewScene.AddBoundingBox(rsn.Pose.AaBB, Color.Yellow);
            }
        }
        
    }
}
